//: Playground - noun: a place where people can play

import UIKit

/**
 共同点
 a.定义存储属性
 b.定义函数
 c.定义下标,使用下表访问自己的值
 d.定义初始化设置自己的初始化状态
 e.扩展自己的功能
 f.实现协议提供某种特定的标准功能
 
 不同点(类有更多功能)
 a.类可以继承,结构体不能继承
 b.类能够在运行时检查和解释类实例的类型
 c.Deinitializers使一个类的实例来释放任何资源分配
 d.类有引用计数,允许对象被多次引用
 */

class StudentC {

    /**
     在类中定义属性必须要注意,如果你定义的存储属性不是可选值类型,必须进行初始化,不然编译会报错,但是结构体不会报错,因为系统默认会给结构体创建初始化方法
     */
    var name:String!;
    
    static var des:String = "学生的类"
    
    func getName() -> String {
        
        return name;
    }
    
    /**
     类可以使用关键字static class 修饰方法,但是结构体只能使用关键字static修饰
     */

    class func describe() -> String {
    
        return des;
    }
    
    static func getClassDescribe() -> String {
    
        return des;
    }
    
    var names:[String] = ["1","2","3","4","5"];
    
    subscript (index:Int) -> String? {
    
        get {
        
            if names.count <= index {
            
                return nil;
            }
            
            return names[index];
        }
    }
    
}

struct StudentS {

    var name:String;
    static var des:String = "学生的结构体";
    static func describe() -> String {
    
        return des;
    }
    
    var names:[String] = ["1","2","3","4","5"];
    
    subscript (index:Int) -> String? {
        
        get {
            
            if names.count <= index {
                
                return nil;
            }
            
            return names[index];
        }
    }
}

extension StudentC {

    func desc() -> String {
        
        return "学生" + self.name;
    }
}

extension StudentS {
    
    func desc() -> String {
        
        return "学生" + self.name;
    }
}

protocol Capacity {

    func deaw();
}

class StudentZ:Capacity {

    internal func deaw() {
        
    }
    
    var name:String
    init(name:String) {
        
        self.name = name;
    }
}

struct StudentQ:Capacity {

    internal func deaw() {
        
    }
    
    var name: String;
}

class Person {

    var name:String
    
    init(name: String) {
        
        self.name = name;
    }
}

class StudentW: Person {

    var score: Float
    
    init(name: String, score: Float) {
        
        self.score = score;
        super.init(name: name);
        self.name = name;
    }
}

/**
 结构体和枚举都是值类型,但是默认值类型的对象方法不能修改属性值,但是要修改怎么办呢?就必须在函数前面加mutating
 */

protocol Action {

    var myY:Int{ mutating get }
}

struct Point1 {

    var x: Int;
    var y: Int;
    
    // 结构体或者枚举修改值必须在函数前面加mutating
    mutating func modifyX(x: Int) {
    
        self.x = x;
    }
    
    var myY: Int {
    
        mutating get {
        
            self.y = self.y * 2;
            
            return y;
        }
    }
}

struct Point2 {

    var x = 0.0, y = 0.0;
    
    mutating func moveBy (x deltaX: Double, y delatY: Double) {
    
        self = Point2(x: x + deltaX, y: y + delatY);
    }
}

var p2 = Point2(x: 0.0, y: 3.0);
var p3 = p2.moveBy(x: 2.0, y: 4.0);

enum TriStateSwitch {

    case off, low, high;
    
    mutating func next() {
    
        switch self {
        case .off:
            
            self = .low;
            
        case .low:
            
            self = .high;
        case .high:
            
            self = .off;
        }
    }
}

/**
检测两个对象地址是不是相同，类是引用类型,结构体是值类型,不能使用===/!== 判断地址
 */

let student1 = StudentC();
let student2 = student1;
if student1 === student2{
    print("地址相同")
}

/**
 
 Deinitializers使一个类的实例来释放任何资源分配，结构体没有deinit 方法
 */

class StudentF {

    var name: String
    
    init(name: String) {
        
        self.name = name;
    }
    
    deinit {
        
        // 释放资源
    }
}

/**
 什么时候用结构体
 
 1.该结构的主要目的是封装几个相对简单的数据值
 2.如果你希望你的结构在传递的时候被赋值而不是引用
 3.希望结构在传递的时候,内部的属性也被复制而不是引用
 4.不需要继承属性或者方法
 主要应用场景(只包含非对象类型)
 
 1.定义Size
 2.定义范围Range
 3.定义坐标XYZ
 ...
 b.什么时候用类
 
 除了上面的场景外,其余都使用类对象。
 
 */


